//Verilog HDL for "Lib6710Project", "SysControl" "verilog"

module SysControl(
	CLK, 
	RESET, 
	EPROM_OUT, 
	EPROM_DONE, 
	SRAM_WEB, 
	SRAM_BLEB, 
	SRAM_BHEB, 
	SRAM_OEB,
	SRAM_IN,
	SRAM_OUT,
	MEM_ADDR, 
	DSUB_OUT,
	DSUB_VSYNCB,
	DSUB_HSYNCB,
	VGA_CLK, 
	VGA_RST, 
	VGA_MEM, 
	VGA_ADDR, 
	VGA_READ,
	VGA_OUT,
	VGA_VSYNCB,
	VGA_HSYNCB,
	PS2_CLK,
	PS2_DATA,
	CPU_CLK,
	CPU_RSTB,
	CPU_VSYNCB,
	CPU_SRAM_READB,
	CPU_SRAM_WRITEB,
	CPU_SRAM_ADDR,
	CPU_SRAM_IN,
	CPU_SRAM_OUT,
	CPU_PS2_CLK,
	CPU_PS2_DATA,
	TEST_PATTERN
);

	//Signals for Clock and Reset Button
	input CLK;
	input RESET;
	wire CLK;
	wire RESET;
	
	//Signals for Memory Units
	input [7:0] EPROM_OUT;
	output EPROM_DONE;
	output SRAM_WEB;
	output SRAM_BLEB;
	output SRAM_BHEB;
	output SRAM_OEB;
	output [15:0] SRAM_IN;
	input [15:0] SRAM_OUT;
	output [18:0] MEM_ADDR;
	wire [7:0] EPROM_OUT;
	reg EPROM_DONE;
	reg SRAM_WEB;
	reg SRAM_BLEB;
	reg SRAM_BHEB;
	reg SRAM_OEB;
	reg [15:0] SRAM_IN;
	wire [15:0] SRAM_OUT;
	reg [18:0] MEM_ADDR;
    
	//Signals for VGA DSUB Connector
	output[7:0] DSUB_OUT;
	output DSUB_VSYNCB;
	output DSUB_HSYNCB;
	wire[7:0] DSUB_OUT;
	wire DSUB_VSYNCB;
	wire DSUB_HSYNCB;
	
	//Signals for VGA
	output VGA_CLK;
	output VGA_RST;
	output [15:0] VGA_MEM;
	input [17:0] VGA_ADDR;
	input VGA_READ;
	input[7:0] VGA_OUT;
	input VGA_VSYNCB;
	input VGA_HSYNCB;
	wire VGA_CLK;
	wire VGA_RST;
	reg [15:0] VGA_MEM;
	wire [17:0] VGA_ADDR;
	wire VGA_READ;
	wire[7:0] VGA_OUT;
	wire VGA_VSYNCB;
	wire VGA_HSYNCB;
	
	//Signals for PS/2
	input PS2_CLK;
	input PS2_DATA;
	wire PS2_CLK;
	wire PS2_DATA;
	
	//Signals for CPU
	output CPU_CLK;
	output CPU_RSTB;
	output CPU_VSYNCB;
	input CPU_SRAM_READB;
	input CPU_SRAM_WRITEB;
	input[17:0] CPU_SRAM_ADDR;
	output[15:0] CPU_SRAM_OUT;
	input[15:0] CPU_SRAM_IN;
	output CPU_PS2_CLK;
	output CPU_PS2_DATA;
	reg CPU_CLK;
	reg CPU_RSTB;
	wire CPU_VSYNCB;
	wire CPU_SRAM_READB;
	wire CPU_SRAM_WRITEB;
	wire[17:0] CPU_SRAM_ADDR;
	wire[15:0] CPU_SRAM_OUT;
	wire[15:0] CPU_SRAM_IN;
	wire CPU_PS2_CLK;
	wire CPU_PS2_DATA;
	
	//Test signals
	input[15:0] TEST_PATTERN;
	wire[15:0] TEST_PATTERN;
	
	//Internal signals and flip flops
	reg EPROM_CLK_DIV0;
	reg EPROM_CLK_DIV1;
	reg EPROM_CLK;
	reg [18:0] EPROM_LOAD_COUNT;
	reg CPU_CLK_ENABLE;
	
	//========== EPROM ==========
	
	// Generate EPROM Clock Signal from 25MHz by dividing the clock lots of times
	always @(posedge CLK, posedge RESET) begin
		if (RESET == 1'b1) begin
			EPROM_CLK_DIV0 <= 1'b0;
			EPROM_CLK_DIV1 <= 1'b0;
			EPROM_CLK <= 1'b0;
                     
		end
		else begin
			EPROM_CLK_DIV0 <= ~EPROM_CLK_DIV0;
			if (EPROM_CLK_DIV0 == 1'b1) begin
				EPROM_CLK_DIV1 <= ~EPROM_CLK_DIV1;
			end
			if (EPROM_CLK_DIV1 == 1'b1) begin
				EPROM_CLK <= ~EPROM_CLK;
			end
		end
	end

	//========== SRAM ========== 
	
	//SRAM logic is all intertwined with EPROM and CPU.  See CPU and Mixed Module sections.
	
	//========== DSUB ==========
    
	//Pipe VGA signals out to DSUB
	assign DSUB_OUT = VGA_OUT;
	assign DSUB_VSYNCB = VGA_VSYNCB;
	assign DSUB_HSYNCB = VGA_HSYNCB;
    
	//========== VGA ==========
	
	//Pass VGA clock and reset along unmodified
	assign VGA_CLK = CLK;
	assign VGA_RST = RESET;
	
	//========== PS/2 ==========
	
	//PS/2 information just gets passed directly to cpu. See CPU section.
	
	//========== CPU ==========
	
	//Generate a CPU clock that is DOWN-DOWN-UP-DOWN, 
	//and only turns on when the EPROM programming is done
	always @(posedge CLK, posedge RESET) begin
		if (RESET == 1'b1) begin
			CPU_CLK <= 1'b1; //Start at 1 so that the VGA gets the even clocks
		end
		else begin
			CPU_CLK <= ~CPU_CLK;
		end
	end
	
	//Pass reset along to cpu (its active low)
	//assign CPU_RSTB = ~RESET;
	
	//Give the CPU the SRAM data line all the time
	assign CPU_SRAM_OUT = SRAM_OUT;
	
	//Pass ps/2 information directly to CPU
	assign CPU_PS2_CLK = PS2_CLK;
	assign CPU_PS2_DATA = PS2_DATA;
	
	//Pass VSYNC signal to CPU
	assign CPU_VSYNCB = VGA_VSYNCB;
	
	//========== Mixed Module Logic ==========
	
	//EPROM Programmer
	//Program memory whenever the load counter is not at its maximum value
	//SRAM_BLEB and SRAM_BHEB select lower and upper bytes
	always @(posedge EPROM_CLK, posedge RESET)
	begin
		if (RESET == 1'b1) begin
			EPROM_LOAD_COUNT <= 19'b0;
			EPROM_DONE <= 1'b0;
			SRAM_WEB <= 1'b1;
			SRAM_BLEB <= 1'b1;
			SRAM_BHEB <= 1'b1;
			SRAM_OEB <= 1'b1;
                        CPU_RSTB <= 1'b0;
		end
		else if (EPROM_LOAD_COUNT != 19'h7FFFF) begin
			EPROM_LOAD_COUNT <= EPROM_LOAD_COUNT + 1;
			EPROM_DONE <= 1'b0;
			SRAM_WEB <= 1'b0;
			SRAM_BLEB <= EPROM_LOAD_COUNT[0];
			SRAM_BHEB <= ~EPROM_LOAD_COUNT[0];
			SRAM_OEB <= 1'b1;
			CPU_RSTB <= 1'b0;
		end
		else begin
			EPROM_DONE <= 1'b1;
                        SRAM_WEB <= CPU_SRAM_WRITEB;
			SRAM_BLEB <= 1'b0;
			SRAM_BHEB <= 1'b0;
			SRAM_OEB <= ~CPU_SRAM_WRITEB;
			CPU_RSTB <= 1'b1;
		end
	end

	//Memory and Address Line Selection
	always
	begin
		//The EPROM and SRAM share the address. Thus, MEM_ADDR is the name of the signal.
		//SRAM's version is shifted left by one bit physically
		//
		//If something happens to the VGA, and it gets off sync, it will be
		//much easier to debug if the CPU has precedence over the VGA for
		//memory access.  So, if CPU_SRAM_READB or CPU_SRAM_WRITEB are asserted,
		//the CPU gets memory access immediately
		if (EPROM_DONE == 1'b0) begin
			MEM_ADDR <= EPROM_LOAD_COUNT;	
			VGA_MEM <= TEST_PATTERN;
			SRAM_IN <= {EPROM_OUT,EPROM_OUT};
		end
		else if (CPU_SRAM_READB == 1'b0 || CPU_SRAM_WRITEB == 1'b0) begin
			MEM_ADDR <= CPU_SRAM_ADDR;
			VGA_MEM <= 16'b0;
			SRAM_IN <= CPU_SRAM_IN;
		end
		else begin//if (VGA_READ == 1'b1) begin
			MEM_ADDR <= {VGA_ADDR, 1'b0};			
			VGA_MEM <= SRAM_OUT;
			SRAM_IN <= 16'b0;
		end
	end

endmodule
